# !/usr/bin/env python
# -*- coding: utf-8 -*-
"""
 -------------------------------------------------
    File Name:     startup.py
    Description:   运行相关的封装
 -------------------------------------------------
 """

import os
import shutil
import subprocess
from typing import Literal

import pytest

from apitesting.common.util.logger import log
# from commons.utils.path_utils import REPORT_JSON, REPORT_HTML, CASES_FILE

from apitesting.common.db.redis_handler import redis_handler
from apitesting.src import case_manager
from apitesting.src.case_manager import CaseDataHandler
from apitesting.config import paths
from apitesting.config import settings
from apitesting.common.util.return_time import get_time as time_
from apitesting.common.file.yaml_handler import yaml_handler as ReadYaml


def validate_case_path(case_path: str = None) -> str:
    """验证并处理用例路径参数"""
    # 确定用例的默认路径
    default_case_path = paths.TEST_CASE_DIR.as_posix() + "/" + settings.project.name

    if case_path:
        if '::' not in case_path:
            raise ValueError(
                '用例收集失败, 请检查路径参数 \n'
                '类用例说明: \n'
                '\t1. 项目目录下没有多级目录: case_path = "文件名::类名" \n'
                '\t2. 项目目录下有多级目录: case_path = "目录名/.../文件名::类名" \n'
                '函数用例说明: \n'
                '\t1. 项目目录下没有多级目录: case_path = "文件名::类名::函数名" \n'
                '\t2. 项目目录下有多级目录: case_path = "目录名/.../文件名::函数名"'
            )
        sep = os.path.sep
        case_path = case_path.replace('/', sep)
        run_path = os.sep.join([default_case_path, case_path])
    else:
        run_path = default_case_path
    return run_path


def configure_html_report(html_report: bool = True, report_file: str = None) -> list:
    """配置HTML报告生成参数"""
    html_report_filename = f'{settings.project.name}_{time_.get_now_time()}.html'
    if html_report:
        if not os.path.exists(report_file or paths.HTML_REPORT_DIR):
            os.makedirs(paths.HTML_REPORT_DIR)
        return [
            f'--html={os.path.join(paths.HTML_REPORT_DIR, html_report_filename)}',
            '--self-contained-html',
        ]
    return []


def configure_allure_report(allure: bool = True, allure_clear: bool = True) -> list:
    """配置Allure报告生成参数"""
    if allure:
        run_args = [f'--alluredir={paths.ALLURE_RESULTS_DIR}']
        if allure_clear:
            run_args.append('--clean-alluredir')
        return run_args
    return []


def configure_max_fail(max_fail: int) -> list:
    """配置最大失败案例数参数"""
    if max_fail != 0:
        return [f'--maxfail {max_fail}']
    return []


def configure_additional_args(args: tuple, kwargs: dict, run_args: list) -> list:
    """处理额外的位置参数和关键字参数"""
    if args:
        for i in args:
            if i not in run_args:
                run_args.append(i)
    if kwargs:
        for k, v in kwargs.items():
            for i in run_args:
                if '=' in i and k in i:
                    run_args.remove(i)
                    run_args.append(f'{k}={v}')
    return run_args


def format_run_args(run_args: list) -> str:
    """格式化运行参数，确保参数值被正确地包含在引号中"""
    format_run_args = []

    for i in run_args:
        if '=' in i:
            i_split = i.split('=')
            new_i = i.replace(i_split[1], f'"{i_split[1]}"')
            format_run_args.append(new_i)
        else:
            format_run_args.append(i)
    return ' '.join(
        i if os.path.isdir(i) or i.startswith('-') else f'"{i}"' for i in format_run_args
    )


def process_and_notify_test_results(html_report=None, html_report_filename=None):
    """
    处理测试结果并发送通知

    :param html_report: 是否发送 HTML 报告
    :param html_report_filename: HTML 报告文件名
    """
    try:
        # 获取最新的 YAML 报告文件
        yaml_report_files = os.listdir(paths.yaml_report_dir)
        yaml_report_files.sort()
        latest_yaml_report_file = yaml_report_files[-1]
        test_result = ReadYaml(file_url=paths.yaml_report_dir + latest_yaml_report_file)

        # # 发送报告
        # if html_report and config.EMAIL_SEND:
        #     SendEmail(test_result, html_report_filename).send_report()
        #
        # # 发送钉钉消息
        # if config.DINGDING_SEND:
        #     DingDing(test_result).send()
        #
        # # 发送飞书消息
        # if config.FEISHU_SEND:
        #     FeiShu(test_result).send()
        #
        # # 发送企业微信消息
        # if config.WECHAT_SEND:
        #     WeChat(test_result).send()
    except Exception as e:
        log.error(f'处理测试结果失败: {e}')


def generate_and_serve_allure_reports(allure, allure_serve, cache_path):
    """
    生成并服务 Allure 报告。

    :param allure: 是否启用 Allure 报告生成
    :param allure_serve: 是否启动 Allure 服务
    :param cache_path: 包含报告路径的对象
    """
    if allure:
        # 检查 Allure 报告目录是否存在
        if os.path.exists(cache_path.allure_results_dir):
            # 检查环境文件是否存在，如果不存在则复制
            if not os.path.exists(cache_path.allure_report_env_file):
                shutil.copyfile(cache_path.allure_env_file, cache_path.allure_report_env_file)

        # 如果启用了 Allure 服务，则生成并启动服务
        if allure_serve:
            subprocess.run(
                [
                    'allure-results',
                    'generate',
                    f'{cache_path.allure_results_dir}',
                    '-o',
                    f'{cache_path.allure_html_report_dir}',
                    '--clean',
                ]
            )
            subprocess.run(['allure-results', 'serve', f'{cache_path.allure_results_dir}'])


# def start_run(run_args):
#     # 记录测试运行开始信息
#     log.info('🚀🚀🚀🚀🚀🚀 START RUN 🚀🚀🚀🚀🚀🚀')
#
#     # 运行测试
#     try:
#         # 运行测试
#         pytest.main(run_args)
#     except Exception as e:
#         log.error(f'测试运行失败: {e}')
#         return
#
#     # 记录测试运行结束信息
#     log.info('🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁 FINISH 🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁')


def teardown_run(allure: bool = True, allure_serve: bool = False):
    # 处理测试结果并发送通知
    # process_and_notify_test_results(html_report, html_report_filename)

    # 处理Allure报告生成和启动服务
    generate_and_serve_allure_reports(
        allure=allure,
        allure_serve=allure_serve,
        cache_path=paths
    )


def run(pydantic_verify: bool = True):
    """
    主运行函数，包含用例初始化、缓存清理、用例校验、参数设置及用例执行。
    """
    banner = f"""
         ██     ███████  ██      ██████████ ████████  ████████ ██████████
        ████   ░██░░░░██░██     ░░░░░██░░░ ░██░░░░░  ██░░░░░░ ░░░░░██░░░ 
       ██░░██  ░██   ░██░██         ░██    ░██      ░██           ░██    
      ██  ░░██ ░███████ ░██         ░██    ░███████ ░█████████    ░██    
     ██████████░██░░░░  ░██         ░██    ░██░░░░  ░░░░░░░░██    ░██    
    ░██░░░░░░██░██      ░██         ░██    ░██             ░██    ░██    
    ░██     ░██░██      ░██         ░██    ░████████ ████████     ░██    
    ░░      ░░ ░░       ░░          ░░     ░░░░░░░░ ░░░░░░░░      ░░   
    
    Starting...
    """
    log.info(banner)

    # try:
    #     case_manager.clean_cache_data(clean_cache=False)
    #     log.info("✅ 缓存清理完成")
    # except Exception as e:
    #     log.warning(f"⚠️ 缓存清理过程中出现问题: {e}")



    # 校验用例数据
    try:
        case_manager.validate_case_data_from_redis(pydantic_verify=pydantic_verify)
        log.info("✅ 用例校验完成")
    except Exception as e:
        log.error(f"❌ 用例校验失败: {e}")
        return  # 终止运行

    # # 设置运行参数
    # try:
    #     run_args = setup_check_run_args()
    #     log.info(f"✅ 运行参数设置成功: {run_args}")
    # except Exception as e:
    #     log.error(f"❌ 运行参数设置失败: {e}")
    #     return  # 终止运行

    # 执行测试用例
    # try:
    #     start_run(run_args)
    #     log.info("🏁 测试用例执行完成")
    # except Exception as e:
    #     log.error(f"❌ 测试用例执行失败: {e}")


if __name__ == '__main__':
    run()
